// Copyright 2021-2025 The Connect Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import { create, createRegistry } from "@bufbuild/protobuf";

import {
  invokeWithPromiseClient,
  UnaryRequestSchema,
  ServerStreamRequestSchema,
  ClientStreamRequestSchema,
  BidiStreamRequestSchema,
  UnimplementedRequestSchema,
  IdempotentUnaryRequestSchema,
  ConformancePayload_RequestInfoSchema,
  ClientCompatResponseSchema,
  ClientErrorResultSchema,
} from "@connectrpc/connect-conformance";
import { createTransport } from "./transport.js";
import { createWorkerHandler } from "./handler.js";
import {
  InvokeRequestSchema,
  InvokeService,
} from "./gen/invoke/v1/invoke_pb.js";

export default createWorkerHandler({
  jsonOptions: {
    registry: createRegistry(
      UnaryRequestSchema,
      ServerStreamRequestSchema,
      ClientStreamRequestSchema,
      BidiStreamRequestSchema,
      UnimplementedRequestSchema,
      IdempotentUnaryRequestSchema,
      ConformancePayload_RequestInfoSchema,
    ),
  },
  routes({ service }) {
    service(InvokeService, {
      async invoke(req) {
        if (!req.request) {
          throw new Error(
            "Missing " + InvokeRequestSchema.field.request.toString(),
          );
        }
        const res = create(ClientCompatResponseSchema, {
          testName: req.request.testName,
        });
        try {
          const invokeResult = await invokeWithPromiseClient(
            createTransport(req.request),
            req.request,
          );
          res.result = { case: "response", value: invokeResult };
        } catch (e) {
          res.result = {
            case: "error",
            value: create(ClientErrorResultSchema, {
              message: (e as Error).message,
            }),
          };
        }
        return { response: res };
      },
    });
  },
});
